﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Threading;

namespace RxjhServer
{
	public class Timer
	{
		private DateTime m_Next;

		private TimeSpan m_Delay;

		private TimeSpan m_Interval;

		private bool m_Running;

		private int m_Index;

		private int m_Count;

		private TimerPriority m_Priority;

		private List<Timer> m_List;

		private static Dictionary<string, TimerProfile> m_Profiles = new Dictionary<string, TimerProfile>();

		private static Queue<Timer> m_Queue = new Queue<Timer>();

		private static int m_BreakCount = 20000;

		private static int m_QueueCountAtSlice;

		private bool m_Queued;

		private static string FormatDelegate(Delegate callback)
		{
			if (callback == null)
			{
				return "null";
			}
			return string.Format("{0}.{1}", callback.Method.DeclaringType.FullName, callback.Method.Name);
		}

		public static void DumpInfo(TextWriter tw)
		{
			Timer.TimerThread.DumpInfo(tw);
		}

		public TimerPriority Priority
		{
			get
			{
				return this.m_Priority;
			}
			set
			{
				if (this.m_Priority != value)
				{
					this.m_Priority = value;
					if (this.m_Running)
					{
						Timer.TimerThread.PriorityChange(this, (int)this.m_Priority);
					}
				}
			}
		}

		public DateTime Next
		{
			get
			{
				return this.m_Next;
			}
		}

		public TimeSpan Delay
		{
			get
			{
				return this.m_Delay;
			}
			set
			{
				this.m_Delay = value;
			}
		}

		public TimeSpan Interval
		{
			get
			{
				return this.m_Interval;
			}
			set
			{
				this.m_Interval = value;
			}
		}

		public bool Running
		{
			get
			{
				return this.m_Running;
			}
			set
			{
				if (value)
				{
					this.Start();
					return;
				}
				this.Stop();
			}
		}

		public static Dictionary<string, TimerProfile> Profiles
		{
			get
			{
				return Timer.m_Profiles;
			}
		}

		public TimerProfile GetProfile()
		{
			string text = this.ToString();
			if (text == null)
			{
				text = "null";
			}
			TimerProfile timerProfile = null;
			Timer.m_Profiles.TryGetValue(text, out timerProfile);
			if (timerProfile == null)
			{
				timerProfile = (Timer.m_Profiles[text] = new TimerProfile());
			}
			return timerProfile;
		}

		public static int BreakCount
		{
			get
			{
				return Timer.m_BreakCount;
			}
			set
			{
				Timer.m_BreakCount = value;
			}
		}

		public static void Slice()
		{
			lock (Timer.m_Queue)
			{
				Timer.m_QueueCountAtSlice = Timer.m_Queue.Count;
				int num = 0;
				Stopwatch stopwatch = null;
				while (num < Timer.m_BreakCount && Timer.m_Queue.Count != 0)
				{
					if (World.jlMsg == 1)
					{
						Form1.WriteLine(0, "Slice");
					}
					Timer timer = Timer.m_Queue.Dequeue();
					TimerProfile profile = timer.GetProfile();
					if (profile != null)
					{
						if (stopwatch == null)
						{
							stopwatch = Stopwatch.StartNew();
						}
						else
						{
							stopwatch.Start();
						}
					}
					timer.OnTick();
					timer.m_Queued = false;
					num++;
					if (profile != null)
					{
						profile.RegTicked(stopwatch.Elapsed);
						stopwatch.Reset();
					}
				}
			}
		}

		public Timer(TimeSpan delay) : this(delay, TimeSpan.Zero, 1)
		{
		}

		public Timer(TimeSpan delay, TimeSpan interval) : this(delay, interval, 0)
		{
		}

		public virtual bool DefRegCreation
		{
			get
			{
				return true;
			}
		}

		public virtual void RegCreation()
		{
			TimerProfile profile = this.GetProfile();
			if (profile != null)
			{
				profile.RegCreation();
			}
		}

		public Timer(TimeSpan delay, TimeSpan interval, int count)
		{
			this.m_Delay = delay;
			this.m_Interval = interval;
			this.m_Count = count;
			if (this.DefRegCreation)
			{
				this.RegCreation();
			}
		}

		public override string ToString()
		{
			return base.GetType().FullName;
		}

		public static TimerPriority ComputePriority(TimeSpan ts)
		{
			if (ts >= TimeSpan.FromMinutes(1.0))
			{
				return TimerPriority.FiveSeconds;
			}
			if (ts >= TimeSpan.FromSeconds(10.0))
			{
				return TimerPriority.OneSecond;
			}
			if (ts >= TimeSpan.FromSeconds(5.0))
			{
				return TimerPriority.TwoFiftyMS;
			}
			if (ts >= TimeSpan.FromSeconds(2.5))
			{
				return TimerPriority.FiftyMS;
			}
			if (ts >= TimeSpan.FromSeconds(1.0))
			{
				return TimerPriority.TwentyFiveMS;
			}
			if (ts >= TimeSpan.FromSeconds(0.5))
			{
				return TimerPriority.TenMS;
			}
			return TimerPriority.EveryTick;
		}

		public static Timer DelayCall(TimeSpan delay, TimerCallback callback)
		{
			return Timer.DelayCall(delay, TimeSpan.Zero, 1, callback);
		}

		public static Timer DelayCall(TimeSpan delay, TimeSpan interval, TimerCallback callback)
		{
			return Timer.DelayCall(delay, interval, 0, callback);
		}

		public static Timer DelayCall(TimeSpan delay, TimeSpan interval, int count, TimerCallback callback)
		{
			Timer timer = new Timer.DelayCallTimer(delay, interval, count, callback);
			if (count == 1)
			{
				timer.Priority = Timer.ComputePriority(delay);
			}
			else
			{
				timer.Priority = Timer.ComputePriority(interval);
			}
			timer.Start();
			return timer;
		}

		public static Timer DelayCall(TimeSpan delay, TimerStateCallback callback, object state)
		{
			return Timer.DelayCall(delay, TimeSpan.Zero, 1, callback, state);
		}

		public static Timer DelayCall(TimeSpan delay, TimeSpan interval, TimerStateCallback callback, object state)
		{
			return Timer.DelayCall(delay, interval, 0, callback, state);
		}

		public static Timer DelayCall(TimeSpan delay, TimeSpan interval, int count, TimerStateCallback callback, object state)
		{
			Timer timer = new Timer.DelayStateCallTimer(delay, interval, count, callback, state);
			if (count == 1)
			{
				timer.Priority = Timer.ComputePriority(delay);
			}
			else
			{
				timer.Priority = Timer.ComputePriority(interval);
			}
			timer.Start();
			return timer;
		}

		public void Start()
		{
			if (!this.m_Running)
			{
				this.m_Running = true;
				Timer.TimerThread.AddTimer(this);
				TimerProfile profile = this.GetProfile();
				if (profile != null)
				{
					profile.RegStart();
				}
			}
		}

		public void Stop()
		{
			if (this.m_Running)
			{
				this.m_Running = false;
				Timer.TimerThread.RemoveTimer(this);
				TimerProfile profile = this.GetProfile();
				if (profile != null)
				{
					profile.RegStopped();
				}
			}
		}

		protected virtual void OnTick()
		{
		}

		public class TimerThread
		{
			private static Queue m_ChangeQueue = Queue.Synchronized(new Queue());

			private static DateTime[] m_NextPriorities = new DateTime[8];

			private static TimeSpan[] m_PriorityDelays = new TimeSpan[]
			{
				TimeSpan.Zero,
				TimeSpan.FromMilliseconds(10.0),
				TimeSpan.FromMilliseconds(25.0),
				TimeSpan.FromMilliseconds(50.0),
				TimeSpan.FromMilliseconds(250.0),
				TimeSpan.FromSeconds(1.0),
				TimeSpan.FromSeconds(5.0),
				TimeSpan.FromMinutes(1.0)
			};

			private static List<Timer>[] m_Timers = new List<Timer>[]
			{
				new List<Timer>(),
				new List<Timer>(),
				new List<Timer>(),
				new List<Timer>(),
				new List<Timer>(),
				new List<Timer>(),
				new List<Timer>(),
				new List<Timer>()
			};

			public static void DumpInfo(TextWriter tw)
			{
				for (int i = 0; i < 8; i++)
				{
					tw.WriteLine("Priority: {0}", (TimerPriority)i);
					tw.WriteLine();
					Dictionary<string, List<Timer>> dictionary = new Dictionary<string, List<Timer>>();
					for (int j = 0; j < Timer.TimerThread.m_Timers[i].Count; j++)
					{
						Timer timer = Timer.TimerThread.m_Timers[i][j];
						string key = timer.ToString();
						List<Timer> list;
						dictionary.TryGetValue(key, out list);
						if (list == null)
						{
							list = (dictionary[key] = new List<Timer>());
						}
						list.Add(timer);
					}
					foreach (KeyValuePair<string, List<Timer>> current in dictionary)
					{
						string key2 = current.Key;
						List<Timer> value = current.Value;
						tw.WriteLine("Type: {0}; Count: {1}; Percent: {2}%", key2, value.Count, (int)(100.0 * ((double)value.Count / (double)Timer.TimerThread.m_Timers[i].Count)));
					}
					tw.WriteLine();
					tw.WriteLine();
				}
			}

			public static void Change(Timer t, int newIndex, bool isAdd)
			{
				Timer.TimerThread.m_ChangeQueue.Enqueue(Timer.TimerThread.TimerChangeEntry.GetInstance(t, newIndex, isAdd));
			}

			public static void AddTimer(Timer t)
			{
				Timer.TimerThread.Change(t, (int)t.Priority, true);
			}

			public static void PriorityChange(Timer t, int newPrio)
			{
				Timer.TimerThread.Change(t, newPrio, false);
			}

			public static void RemoveTimer(Timer t)
			{
				Timer.TimerThread.Change(t, -1, false);
			}

			private static void ProcessChangeQueue()
			{
				while (Timer.TimerThread.m_ChangeQueue.Count > 0)
				{
					if (World.jlMsg == 1)
					{
						Form1.WriteLine(0, "ProcessChangeQueue");
					}
					Timer.TimerThread.TimerChangeEntry timerChangeEntry = (Timer.TimerThread.TimerChangeEntry)Timer.TimerThread.m_ChangeQueue.Dequeue();
					Timer timer = timerChangeEntry.m_Timer;
					int newIndex = timerChangeEntry.m_NewIndex;
					if (timer.m_List != null)
					{
						timer.m_List.Remove(timer);
					}
					if (timerChangeEntry.m_IsAdd)
					{
						timer.m_Next = DateTime.Now + timer.m_Delay;
						timer.m_Index = 0;
					}
					if (newIndex >= 0)
					{
						timer.m_List = Timer.TimerThread.m_Timers[newIndex];
						timer.m_List.Add(timer);
					}
					else
					{
						timer.m_List = null;
					}
					timerChangeEntry.Free();
				}
			}

			public void TimerMain()
			{
				while (true)
				{
					if (World.jlMsg == 1)
					{
						Form1.WriteLine(0, "TimerMain");
					}
					Thread.Sleep(10);
					Timer.TimerThread.ProcessChangeQueue();
					for (int i = 0; i < Timer.TimerThread.m_Timers.Length; i++)
					{
						DateTime now = DateTime.Now;
						if (now < Timer.TimerThread.m_NextPriorities[i])
						{
							break;
						}
						Timer.TimerThread.m_NextPriorities[i] = now + Timer.TimerThread.m_PriorityDelays[i];
						for (int j = 0; j < Timer.TimerThread.m_Timers[i].Count; j++)
						{
							Timer timer = Timer.TimerThread.m_Timers[i][j];
							if (!timer.m_Queued && now > timer.m_Next)
							{
								timer.m_Queued = true;
								lock (Timer.m_Queue)
								{
									Timer.m_Queue.Enqueue(timer);
								}
								if (timer.m_Count != 0 && ++timer.m_Index >= timer.m_Count)
								{
									timer.Stop();
								}
								else
								{
									timer.m_Next = now + timer.m_Interval;
								}
							}
						}
					}
				}
			}

			private class TimerChangeEntry
			{
				public Timer m_Timer;

				public int m_NewIndex;

				public bool m_IsAdd;

				private static Queue<Timer.TimerThread.TimerChangeEntry> m_InstancePool = new Queue<Timer.TimerThread.TimerChangeEntry>();

				private TimerChangeEntry(Timer t, int newIndex, bool isAdd)
				{
					this.m_Timer = t;
					this.m_NewIndex = newIndex;
					this.m_IsAdd = isAdd;
				}

				public void Free()
				{
				}

				public static Timer.TimerThread.TimerChangeEntry GetInstance(Timer t, int newIndex, bool isAdd)
				{
					Timer.TimerThread.TimerChangeEntry timerChangeEntry;
					if (Timer.TimerThread.TimerChangeEntry.m_InstancePool.Count > 0)
					{
						timerChangeEntry = Timer.TimerThread.TimerChangeEntry.m_InstancePool.Dequeue();
						if (timerChangeEntry == null)
						{
							timerChangeEntry = new Timer.TimerThread.TimerChangeEntry(t, newIndex, isAdd);
						}
						else
						{
							timerChangeEntry.m_Timer = t;
							timerChangeEntry.m_NewIndex = newIndex;
							timerChangeEntry.m_IsAdd = isAdd;
						}
					}
					else
					{
						timerChangeEntry = new Timer.TimerThread.TimerChangeEntry(t, newIndex, isAdd);
					}
					return timerChangeEntry;
				}
			}
		}

		private class DelayCallTimer : Timer
		{
			private TimerCallback m_Callback;

			public TimerCallback Callback
			{
				get
				{
					return this.m_Callback;
				}
			}

			public override bool DefRegCreation
			{
				get
				{
					return false;
				}
			}

			public DelayCallTimer(TimeSpan delay, TimeSpan interval, int count, TimerCallback callback) : base(delay, interval, count)
			{
				this.m_Callback = callback;
				this.RegCreation();
			}

			protected override void OnTick()
			{
				if (this.m_Callback != null)
				{
					this.m_Callback();
				}
			}

			public override string ToString()
			{
				return string.Format("DelayCallTimer[{0}]", Timer.FormatDelegate(this.m_Callback));
			}
		}

		private class DelayStateCallTimer : Timer
		{
			private TimerStateCallback m_Callback;

			private object m_State;

			public TimerStateCallback Callback
			{
				get
				{
					return this.m_Callback;
				}
			}

			public override bool DefRegCreation
			{
				get
				{
					return false;
				}
			}

			public DelayStateCallTimer(TimeSpan delay, TimeSpan interval, int count, TimerStateCallback callback, object state) : base(delay, interval, count)
			{
				this.m_Callback = callback;
				this.m_State = state;
				this.RegCreation();
			}

			protected override void OnTick()
			{
				if (this.m_Callback != null)
				{
					this.m_Callback(this.m_State);
				}
			}

			public override string ToString()
			{
				return string.Format("DelayStateCall[{0}]", Timer.FormatDelegate(this.m_Callback));
			}
		}
	}
}
